--inputs: Port SRC address, MAC SRC address, MAC DST address
--outputs: Port DST address, Broadcast
	--when Broadcast, Port DST is don't care
LIBRARY ieee;
USE ieee.std_logic_1164.all;
--USE ieee.numeric_std.all;
USE ieee.std_logic_arith.all;



ENTITY LUT_David_optimized_V2 IS
	PORT(	Port_SRC	:	IN	STD_LOGIC_VECTOR(1 DOWNTO 0);
			MAC_SRC		:	IN	STD_LOGIC_VECTOR(47 DOWNTO 0);
			MAC_DST		:	IN	STD_LOGIC_VECTOR(47 DOWNTO 0);
			clock		:	IN	STD_LOGIC;
		 	LookUpRdy	: 	OUT STD_LOGIC;
			ReqLookUp	:	IN	STD_LOGIC;
			RESETN		:	IN 	STD_LOGIC;
		    PtrIN		: 	IN	STD_LOGIC_VECTOR (7 DOWNTO 0);
			VlanTag		:	IN	STD_LOGIC_VECTOR (31 DOWNTO 0);
			TagValid	:	IN	STD_LOGIC ;
			
			PtrOUT		: 	OUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			VlanTagOUT	:	OUT	STD_LOGIC_VECTOR (31 DOWNTO 0);
			TagValidOUT	:	OUT	STD_LOGIC ;
			Port_DST	:	OUT	STD_LOGIC_VECTOR(1 DOWNTO 0);
			BCAST		:	OUT	STD_LOGIC
		); 
END LUT_David_optimized_V2;	 


ARCHITECTURE behavior of LUT_David_optimized_V2 is
	TYPE State_type IS (WaitForReq, BusyStart, ReadData, WriteData);
	SIGNAL State : State_type;	
		--memory variables
	SIGNAL	data_memBlock		: STD_LOGIC_VECTOR (63 DOWNTO 0);
	SIGNAL	rdaddress_memBlock	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL	wraddress_memBlock	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL	wren_memBlock		: STD_LOGIC  := '1';
	SIGNAL	q_memBlock			: STD_LOGIC_VECTOR (63 DOWNTO 0);
	SHARED VARIABLE TimeStamp	: STD_LOGIC_VECTOR (13 DOWNTO 0) := (OTHERS => '0');	
	SHARED VARIABLE BigCounter	: INTEGER := 0;
	
	
COMPONENT memBlock 
	PORT
	(
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (63 DOWNTO 0);
		rdaddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wraddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wren		: IN STD_LOGIC  := '1';
		q			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
END COMPONENT;

	

BEGIN
	FSM_transitions:  PROCESS (RESETN, CLOCK)
	VARIABLE X1, X2 : INTEGER;
	BEGIN 	
		IF RESETN = '1' THEN
			State <= WaitForReq;   --If no request, Don't look up
		ELSIF(CLOCK'EVENT AND CLOCK = '1')THEN 
			BigCounter := BigCounter + 1;	--increase AGE	
			
			CASE State IS 
			
			WHEN WaitForReq =>              
				IF ReqLookUp = '0' THEN
					State <= WaitForReq;
					LookUpRdy <= '1';
				ELSE 
					State <= BusyStart;  --After request set rdy bit low
					LookUpRdy <= '0';
				END IF;
				wren_memBlock <= '0';
				
			WHEN BusyStart =>
				State <= ReadData;
				--read LUT using MAC DST address to get Port_DST address
				X2 := CONV_INTEGER(UNSIGNED(MAC_DST)) mod 255;
				rdaddress_memBlock <= CONV_STD_LOGIC_VECTOR(X2, 8); 
				wren_memBlock <= '1';
				
			WHEN ReadData =>					
				--then have to compare...ignore collisions for now
					IF q_memBlock(47 DOWNTO 0) = (MAC_DST) THEN
						Port_DST <= q_memBlock(49 DOWNTO 48);
						BCAST <= '0';
					ELSE
						BCAST <= '1';
					END IF;
					wren_memBlock <= '0';
					
			PtrOUT		<= PtrIN;
			VlanTagOUT	<= VlanTag;
			TagValidOUT	<= TagValid;
			State 		<= WriteData;
				
			WHEN WriteData=>
				X1 := CONV_INTEGER(UNSIGNED(MAC_SRC)) mod 255;
				wraddress_memBlock <= CONV_STD_LOGIC_VECTOR(X1, 8);
				TimeStamp := CONV_STD_LOGIC_VECTOR(BigCounter, 14);
				data_memBlock <= (TimeStamp & Port_SRC & MAC_SRC);
				wren_memBlock <= '1';
				State <= WaitForReq;
				LookUpRdy <= '1';
			END CASE;
			
		END IF; 
	END PROCESS;
	
	
MemoryAccess:  memBlock
	PORT MAP (clock, data_memBlock, rdaddress_memBlock, wraddress_memBlock, wren_memBlock, q_memBlock);
END Behavior; 	


LIBRARY ieee;
USE ieee.std_logic_1164.all;

LIBRARY altera_mf;
USE altera_mf.all;

ENTITY memBlock IS
	PORT
	(
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (63 DOWNTO 0);
		rdaddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wraddress	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		wren		: IN STD_LOGIC  := '1';
		q			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
END memBlock;


ARCHITECTURE SYN OF memBlock IS

	SIGNAL sub_wire0	: STD_LOGIC_VECTOR (63 DOWNTO 0);

	COMPONENT altsyncram
	GENERIC (
		address_reg_b				: STRING;
		clock_enable_input_a		: STRING;
		clock_enable_input_b		: STRING;
		clock_enable_output_a		: STRING;
		clock_enable_output_b		: STRING;
		intended_device_family		: STRING;
		lpm_type					: STRING;
		numwords_a					: NATURAL;
		numwords_b					: NATURAL;
		operation_mode				: STRING;
		outdata_aclr_b				: STRING;
		outdata_reg_b				: STRING;
		power_up_uninitialized		: STRING;
		ram_block_type				: STRING;
		read_during_write_mode_mixed_ports		: STRING;
		widthad_a					: NATURAL;
		widthad_b					: NATURAL;
		width_a						: NATURAL;
		width_b						: NATURAL;
		width_byteena_a				: NATURAL
	);
	PORT (
			wren_a		: IN STD_LOGIC ;
			clock0		: IN STD_LOGIC ;
			address_a	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			address_b	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			q_b			: OUT STD_LOGIC_VECTOR (63 DOWNTO 0);
			data_a		: IN STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
	END COMPONENT;


BEGIN
	q    <= sub_wire0(63 DOWNTO 0);

	altsyncram_component : altsyncram
	GENERIC MAP (
		address_reg_b => "CLOCK0",
		clock_enable_input_a => "BYPASS",
		clock_enable_input_b => "BYPASS",
		clock_enable_output_a => "BYPASS",
		clock_enable_output_b => "BYPASS",
		intended_device_family => "Cyclone II",
		lpm_type => "altsyncram",
		numwords_a => 256,
		numwords_b => 256,
		operation_mode => "DUAL_PORT",
		outdata_aclr_b => "NONE",
		outdata_reg_b => "CLOCK0",
		power_up_uninitialized => "FALSE",
		ram_block_type => "M4K",
		read_during_write_mode_mixed_ports => "DONT_CARE",
		widthad_a => 8,
		widthad_b => 8,
		width_a => 64,
		width_b => 64,
		width_byteena_a => 1
	)
	PORT MAP (
		wren_a => wren,
		clock0 => clock,
		address_a => wraddress,
		address_b => rdaddress,
		data_a => data,
		q_b => sub_wire0
	);

END SYN;
